package ch.jamme.conf.def;

import static ch.jamme.util.IntrospectionUtil.*;

import java.lang.reflect.*;
import java.util.*;

import ch.jamme.conf.*;
import ch.jamme.exception.*;
import ch.jamme.util.*;

/**
 * Introspects an Object transforming its properties in a collection of name/value pairs
 * @author Mario Fusco
 */
public class DefaultObjectIntrospector implements ObjectIntrospector {

	/**
	 * Introspects an Object transforming its properties in a collection of name/value pairs
	 * @param fieldSuppressionStrategy The strategy used to decide if a given field should be suppressed or not
	 * @param normalizedClass The object's normalized Class (the one introspected to discover its fields)
	 * @param object The object to be marshalled
	 * @return A Map having as key the name of the introspected field to be marshalled and as value the correspondant field's value
	 */
	public Map<String, Object> introspect(FieldSuppressionStrategy fieldSuppressionStrategy, Class<?> normalizedClass, Object object) throws FieldIntrospectionException {
		Map<String, Object> introspectedValues = new TreeMap<String, Object>();
		
		for (Field field : getAllFields(normalizedClass)) {
			try {
				if (fieldSuppressionStrategy.suppressField(field) || !makeAccesible(field)) continue;
				Object value = IntrospectionUtil.getFieldValue(normalizedClass, field, object);
				if (fieldSuppressionStrategy.suppressField(field, value)) continue;
				introspectedValues.put(field.getName(), value);
			} catch (Exception e) {
				throw new FieldIntrospectionException(field, e);
			}
		}

		modifyIntrospectedValues(normalizedClass, object, introspectedValues);
		return introspectedValues;
	}
	
	/**
	 * Override this method if you want to add values (not yet present in its fields) to the object to be marshalled  
	 * or even modifiy the already introspected values. To do that just modify accordingly the introspectedValues Map   
	 * that contains the values introspected by the field's object mapped with the respective name.
	 * This defualt implementation actually leaves the introspected value Map unchenged
	 * @param normalizedClass The object's normalized Class (the one introspected to discover its fields)
	 * @param object The object to be marshalled
	 * @param introspectedValues The already introspected values extracted from the object's fields
	 */
	protected void modifyIntrospectedValues(Class<?> normalizedClass, Object object, Map<String, Object> introspectedValues) { }
}
